#include "QueryManager.h"
#include <QMutexLocker>
#include <QDebug>

using namespace Common;

QueryManager::QueryManager(Core& core, QObject* parent)
	: QThread(parent)
	, _core(core)
{
}

QueryManager::~QueryManager()
{
	quit();
	wait(10000);
}

void QueryManager::processResponse(QByteArray& data)
{
	if(!_command.isNull())
	{
		_command->processResponse(data);
	}
}

void QueryManager::addCommand(ICommand::SPtr command)
{
	// Если команда не ожидает ответа от устройства, то выполним ее сразу
	if(!command->isWaitingForResponce())
	{
		QString msg = QString("EXEC: %1").arg(command->name());
		qDebug() << msg;
		command->execute(&_core);
		// Закомментировал, чтобы не засирался лог
//		_core.state().logStorage()->addMessage(msg, Log::MessageType::INFO);

		return;
	}

	// Если команда взаимодействует с оборудованием и ожидает от него ответа,
	// то поместим ее в очередь команд для обработки. Каждая такая команда ожидает ответа
	// и либо его получает, либо "вываливается" по таймауту

	QMutexLocker locker(&_queueMutex);
	_waitingQueue.enqueue(command);

	// Запустим поток ождания ответов, если он еще не стартован
	if(!isRunning())
	{
		start();
	}
}

void QueryManager::run()
{
	_queueMutex.lock();

	while(!_waitingQueue.isEmpty())
	{
		_command = _waitingQueue.dequeue();
		_queueMutex.unlock();

		// Запустим обработку запуска команды через invokeMethod
		// Это означает, что данный метод будет выполнен в потоке, которому преданлежит this
		// Т.е. execute() выполнится в главном потоке
		QMetaObject::invokeMethod(this, "execute", Qt::QueuedConnection);

		// Дождемся ответа в потоке ожидания
		waitResponse();

		_command.clear();
		_queueMutex.lock();
	}

	_queueMutex.unlock();
}

void QueryManager::waitResponse()
{
	quint32 timeout = 0;
	quint32 tik = 10;

	while(_command->isWaitingForResponce() && !_command->isTimedOut(timeout))
	{
		QThread::msleep(tik);
		timeout += tik;
	}

	if(_command->isTimedOut(timeout))
	{
		QString msg = QString("TIMEOUT::%1 (%2 msec)").arg(_command->name()).arg(timeout);
		//_core.addLog(msg, Log::MessageType::INFO);
	}
	else
	{
		QString msg = QString("RQST: %1 executed (%2 msec)").arg(_command->name()).arg(timeout);
		//_core.addLog(msg, Log::MessageType::INFO);

		if(!_command->logAfterResponse().isEmpty())
		{
			//_core.addLog(_command->logAfterResponse(), Log::MessageType::INFO);
		}
	}
}

void QueryManager::execute()
{
	QString msg = QString("RESP: %1").arg(_command->name());
	//_core.addLog(msg, Log::MessageType::INFO);
	_command->execute(&_core);

	if(!_command->logAfterExecute().isEmpty())
	{
		//_core.addLog(_command->logAfterExecute(), Log::MessageType::INFO);
	}
}
